import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
import { IS_PUBLIC_KEY } from './metadatas/public.metadata';
import { Reflector } from '@nestjs/core';
import { UserService } from './user/user.service';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private jwtService: JwtService,
    private reflector: Reflector,
    private UserService: UserService
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [context.getHandler(), context.getClass()]);
    if (isPublic) {
      // 💡 See this condition
      return true;
    }
    const request = context.switchToHttp().getRequest();
    const token = this.extractTokenFromHeader(request);
    if (!token) {
      throw new UnauthorizedException('令牌失效(jwt)，请重新登录');
    }
    try {
      const payload = await this.jwtService.verifyAsync(token);
      const { uid, account_id } = payload;
      const ins_token = await this.UserService._token_get(uid, ['id']);
      if (!ins_token) throw new UnauthorizedException('令牌失效，请重新登录');
      const ins_user = await this.UserService._getUserInfo({ account_id });
      if (!ins_user) throw new UnauthorizedException('该用户不存在或已注销，如有疑问请联系管理员');
      request.user = ins_user.toJSON();
    } catch {
      throw new UnauthorizedException('令牌失效，请重新登录');
    }
    return true;
  }

  private extractTokenFromHeader(request: Request): string | undefined {
    const [type, token] = request.headers.authorization?.split(' ') ?? [];
    return type === 'Bearer' ? token : undefined;
  }
}
